import os, sys, platform

APP_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), 'app'))
sys.path.append(APP_ROOT)

import app_config

from manager import Manager

manager = Manager()

@manager.command
def build(is_server=True):
    '''build server/client distribution'''
    if is_server:
        # TODO: change config and publish distribution to dist
        pass
    else:
        # TODO: change config and publish distribution to dist
        pass

@manager.command
def run_app():
    '''run flask app'''
    from app.app_instance import app
    app.run(debug=True, host='0.0.0.0', port=8000)

@manager.command
def run_server(client_id=None, test=None, config=''):
    from gevent import monkey
    monkey.patch_all()
    app_config.APP_USER_CONFIG = app_config.load_config(config)
    if client_id:
        app_config.APP_USER_CONFIG['clientId'] = client_id
        if test:
            app_config.APP_USER_CONFIG['dataDir'] = 'data/client%s' % client_id
            app_config.APP_USER_CONFIG['inbox'] = 'data/client%s/inbox' % client_id
            app_config.APP_USER_CONFIG['tmpPartInbox'] = 'data/client%s/_tmp_part_inbox' % client_id
            app_config.APP_USER_CONFIG['outbox'] = 'data/client%s/outbox' % client_id
    else:
        client_id = app_config.APP_USER_CONFIG['clientId']

    if platform.system().startswith('Windows'):
        os.system("title running file-sync server %s" % client_id)

    from gevent import pywsgi
    from geventwebsocket.handler import WebSocketHandler
    from app.ws_server import app
    server_addr = app_config.APP_USER_CONFIG['remoteServer']
    parts = server_addr.split(':')
    if len(parts) == 2:
        server = pywsgi.WSGIServer(('0.0.0.0', int(parts[1])), app, handler_class=WebSocketHandler)
        server.serve_forever()
    else:
        print('parse server address %s error.' % server_addr)

@manager.command
def run_client(client_id=None, test=None, config=''):
    from gevent import monkey
    monkey.patch_all()
    app_config.APP_USER_CONFIG = app_config.load_config(config)
    if client_id:
        app_config.APP_USER_CONFIG['clientId'] = client_id
        if test:
            app_config.APP_USER_CONFIG['dataDir'] = 'data/client%s' % client_id
            app_config.APP_USER_CONFIG['inbox'] = 'data/client%s/inbox' % client_id
            app_config.APP_USER_CONFIG['tmpPartInbox'] = 'data/client%s/_tmp_part_inbox' % client_id
            app_config.APP_USER_CONFIG['outbox'] = 'data/client%s/outbox' % client_id
    else:
        client_id = app_config.APP_USER_CONFIG['clientId']

    if platform.system().startswith('Windows'):
        os.system("title running file-sync client %s" % client_id)

    from app.ws_client import app
    import gevent
    import signal
    def routine():
        while True:
            gevent.sleep(1)
    gevent.signal(signal.SIGINT, gevent.kill)
    thread = gevent.spawn(routine)
    thread.join()

@manager.command
def generate_files(count=1, send_client='1', recv_clients='2,3', dir='tmp', basename='test_file', size=5000):
    '''python manage.py generate_files --count 1 --send-client '1' --recv-clients '2,3,4' --dir 'data/client1/outbox' --base-name 'test' '''
    tmpl = 'oa_%s_%s_%s_%s'
    try:
        os.makedirs(dir)
    except:
        pass
    for c in range(count):
        file_name = tmpl % (send_client, recv_clients, basename, c + 1)
        file_path = os.path.join(dir, file_name)
        written = 0
        with open(file_path, 'wb') as fh:
            while written < size:
                chunk_size = min(1000000, size - written)
                fh.write(os.urandom(chunk_size))
                written += chunk_size

def run_loop():
    import gevent
    import signal
    def routine():
        while True:
            gevent.sleep(1)

    gevent.signal(signal.SIGINT, gevent.kill)
    thread = gevent.spawn(routine)
    thread.join()

@manager.command
def run_fod(inbox=None, part_inbox=None, outbox=None, part_outbox=None, data_dir=None):
    from app.fod.file_sync_fod import FileSyncFOD, Config
    cfg = Config()
    if data_dir:
        cfg.data_dir = data_dir
    if inbox:
        cfg.inbox = inbox
    if part_inbox:
        cfg.part_inbox = part_inbox
    if outbox:
        cfg.outbox = outbox
    if part_outbox:
        cfg.part_outbox = part_outbox

    fod = FileSyncFOD(cfg)

    run_loop()

def is_lose_event_happened(lose_rate=0.0):
    import random
    d = random.uniform(0, 1)
    return d < lose_rate

@manager.command
def run_gatekeeper(from_dir='', to_dir='', lose_rate=0.0):
    import gevent
    import shutil
    def gatekeeper_routine(from_dir, to_dir):
        if os.path.exists(from_dir):
            for file_name in os.listdir(from_dir):
                try:
                    from_file_path = os.path.join(from_dir, file_name)
                    to_file_path = os.path.join(to_dir, file_name)
                    if is_lose_event_happened(lose_rate):
                        os.remove(from_file_path)
                        logging.info('lose file, removed %s' % from_file_path)
                    else:
                        shutil.move(from_file_path, to_file_path)
                        logging.info('moved %s to %s' % (from_file_path, to_file_path))
                except Exception as ex:
                    logging.error(ex)

    timer = gevent.get_hub().loop.timer(0.0, 0.1)
    timer.start(gatekeeper_routine, from_dir, to_dir)

    run_loop()

@manager.command
def test_socket_limits(num = 1000, server_addr='127.0.0.1:8000'):
    import websocket
    wss = []

    try:
        for i in range(0, num):
            ws = websocket.create_connection('ws://{0}/websocket/stream/down'.format(server_addr))
            wss.append(ws)
    finally:
        print('total openned: %s' % len(wss))

if __name__=='__main__':
    manager.main()
